#include "BakIOAndRecvBak.h"

//************************************
// Method:    	IOBak_ANA				从站解析备份文件
// Programmer:  lww
// Time:		2019/2/16
// Returns:   	bool					true:接收字节数正确；false：错误
// Parameter: 	void * Data				数据区头指针
// Parameter: 	int len					数据包长度
// Parameter: 	short Head				报头
// Parameter: 	short Tail				报尾
//************************************
bool IOBak_ANA(void* Data, int len, short Head, short Tail)
{
#define MEMREAD1(var)	MEMREAD(var, Data)
#define WRONG_DEAL	{\
	printf("Analyze bak IO wrong!\r\n");\
	return false;\
}

	int i;
	int _iLen = 0;
	short Channel_Num = 0;
	short tmp_short;
	short ptr_off;
	unsigned int ChannelID;
	void* Channel_pt = NULL;
	Channel_type_e result;

	//< 校验报头
	MEMREAD1(tmp_short);
	if (tmp_short != Head)
		WRONG_DEAL;

	//< 读出当前指针到报尾的指针的距离，校验报尾
	MEMREAD1(ptr_off);
	memcpy(&tmp_short, (char*)(Data) + ptr_off, sizeof(tmp_short));
	if (tmp_short != Tail)
		WRONG_DEAL;

	//< 备份的通道数量
	MEMREAD1(Channel_Num);

	//< 循环解析各个模块
	for (i = 0; i < Channel_Num; i++)
	{
		MEMREAD1(ChannelID);
		result = Channel_Find(ChannelID, &Channel_pt);

		if (result != NODEFINE)
		{
			MEMREAD1((((DVAV_BASE_Property_t*)Channel_pt)->LastReportTime));
			MEMREAD1((((DVAV_BASE_Property_t*)Channel_pt)->Status));
			MEMREAD1((((DVAV_BASE_Property_t*)Channel_pt)->PreStatus));
			MEMREAD1((((DVAV_BASE_Property_t*)Channel_pt)->AlarmTime));

			if (result == AI_CHA || result == AO_CHA)
			{
				MEMREAD1(((AVChannel_t*)Channel_pt)->Sta_Property);
			}
			else
			{
				MEMREAD1(((DVChannel_t*)Channel_pt)->Sta_Property);
			}
		}
		else
		{
			WRONG_DEAL;
		}
	}

	if (_iLen != (int)(len - sizeof(tmp_short)))
		WRONG_DEAL;

	return true;

#undef WRONG_DEAL
#undef MEMREAD1
}


//************************************
// Method:    	tRecvIOBak				从站接收IO硬点备份线程
// Programmer:  lww
// Time:		2019/3/6
// Returns:   	void *
// Parameter: 	void * arg
//************************************
void *tRecvIOBak(void* arg)
{
#define PACK_MAXNUM	2048

	int sock;
	short Head = 2609;				//< 报头
	short Tail = 3402;				//< 报尾
	char Data2Recv[PACK_MAXNUM];	//< 存放数据包的数组
	short len;

	printf("the Kernel_%s is %d\r\n", "tRecvIOBak_ID", syscall(SYS_gettid));			//< duan20200610
	//< 初始化UDP设置
	if (false == UDP_Init(&sock, RECVBAKIO_PORT, 0, 0, UDP_RECV_STATUS, nullptr)) { return 0; }

	while (1)
	{
		if (SYS_Role == Slave_Role)
		{
			//< 接收数据
			memset(Data2Recv, 0, sizeof(Data2Recv));
			len = (short)UDP_Recv_Any_Bytes(&sock, Data2Recv, PACK_MAXNUM);
			if (len == -1)
				continue;

			//< 解析报文
			IOBak_ANA(Data2Recv, len, Head, Tail);
		}
		else
			RoughDelay_S(2);

	}
	close(sock);//< 断开连接

#undef PACK_MAXNUM
}


//************************************
// Method:    	BakIO_PACK_Make				备份文件打包程序
// Programmer:  lww
// Time:		2019/2/16
// Returns:   	int							打包长度
// Parameter: 	void * Data					数据包头指针
// Parameter: 	short Head					报头
// Parameter: 	short Tail					报尾
// Parameter: 	int Limit_Len				单次数据包长度限制
// Parameter: 	short * SaveChannel_Num		存储的IO通道的数量
//************************************
int BakIO_PACK_Make(void* Data, short Head, short Tail, int Limit_Len, short* SaveChannel_Num, int* TYP_CARD_Count)
{
#define MEMWRITE1(name)	MEMWRITE(name, Data);
	int _iLen = 0;
	short tmp_short;
	/*static int i = 0;*/					//< duan20200502注释
	static int j = 0;
	static int k = 0;
	static int l = 0;
	static int m = 0;
	static int n = 0;
	void* Data1 = NULL;
	Card_Base_t* base = NULL;

	//< 报头
	MEMWRITE1(Head);

	//< 第二个数据存放从下一个数据开始从后数多少个字节为报尾，用于对报文的报尾进行校验，此处先保留该存储位置，稍后再对其进行存储
	Data1 = Data;
	tmp_short = 0;
	MEMWRITE1(tmp_short);
	_iLen = (int)(_iLen - sizeof(tmp_short));

	//< 第三个数据存储本次要广播的模块数量，这个数据等打包完成后最后写入，此处先保留该存储位置，稍后再对其进行存储
	MEMWRITE1(SaveChannel_Num[0]);
	_iLen = (int)(_iLen - sizeof(SaveChannel_Num[0]));

	while ((TYP_CARD_Count[0] < TYP_MAX_CARD) && (_iLen < Limit_Len))
	{
		while ((j < Card_List[TYP_CARD_Count[0]].iCount) && (_iLen < Limit_Len))
		{
			base = (Card_Base_t*)SearchAt(((List_Base_t*)Card_List[TYP_CARD_Count[0]].ppData[0]), j);
			if (base != NULL)
			{
				while ((k < base->IO_Num.AI_Num) && (_iLen < Limit_Len)) { _iLen += BakIO(&base->AIChannel[k], &Data, AI_CHA, SaveChannel_Num); k++; }
				while ((l < base->IO_Num.AO_Num) && (_iLen < Limit_Len)) { _iLen += BakIO(&base->AOChannel[l], &Data, AO_CHA, SaveChannel_Num); l++; }
				while ((m < base->IO_Num.DI_Num) && (_iLen < Limit_Len)) { _iLen += BakIO(&base->DIChannel[m], &Data, DI_CHA, SaveChannel_Num); m++; }
				while ((n < base->IO_Num.DO_Num) && (_iLen < Limit_Len)) { _iLen += BakIO(&base->DOChannel[n], &Data, DO_CHA, SaveChannel_Num); n++; }
				/*if (k >= base->IO_Num.AI_Num) { k = 0; }
				if (l >= base->IO_Num.AO_Num) { l = 0; }
				if (m >= base->IO_Num.DI_Num) { m = 0; }
				if (n >= base->IO_Num.DO_Num) { n = 0; }*/			//< duan20200502注释
			}
			if(k >= base->IO_Num.AI_Num && l >= base->IO_Num.AO_Num && m >= base->IO_Num.DI_Num && n >= base->IO_Num.DO_Num)			//< duan20200502添加
			{
				j++;
				k = 0;
				l = 0;
				m = 0;
				n = 0;
			}
			/*j++;*/					//< duan20200502注释
		}
		if (j >= Card_List[TYP_CARD_Count[0]].iCount)
		{	
			j = 0;
			TYP_CARD_Count[0]++;						//< duan20200502修改
		}
	}
	/*if (i >= TYP_MAX_CARD) { i = 0; }*/	//< duan20200502注释

	//< 写第二个数据
	tmp_short = (short)(_iLen - sizeof(Head) + sizeof(SaveChannel_Num[0]));//< 等于目前已经计数的长度减去报头，加上要广播模块数量数据的长度
	MEMWRITE(tmp_short, Data1);

	//< 写第三个数据
	MEMWRITE(SaveChannel_Num[0], Data1);

	//< 报尾
	MEMWRITE1(Tail);
	return _iLen;
#undef MEMWRITE1
}


//************************************
// Method:    	tBakIOAndRecvBak			主从站备份IO硬点线程
// Programmer:  lww
// Time:		2019/3/6
// Returns:   	void *
// Parameter: 	void * arg
//************************************
void *tBakIOAndRecvBak(void* arg)
{
#define PACK_MAXNUM	2048
#define LIMIT_LEN	512
#define EACH_UDP_PACK_SEND_DELAY_TIME 10	//< Shike20210516 长兴现场发现UDP广播包与包之间没有延时，发送太快，导致从站长时间因丢包无法更新自己的硬点当前值，这样主从切换就很明显会跳变
	int sock;
	static int TYP_CARD_Count = 0;	//< duan20200502添加
	struct sockaddr_in NetC;
	timer_t BakIOData_Timer;
	struct timespec time;
	short Head = 2609;				//< 报头
	short Tail = 3402;				//< 报尾
	char Data2Send[PACK_MAXNUM];	//< 存放数据包的数组
	int _iLen = 0;
	short SaveChannel_Num = 0;		//< 当前数据包广播的IO通道数量
	pthread_t tRecvIOBak_ID = 0;

	printf("the Kernel_%s is %d\r\n", "tBakIOAndRecvBak_ID", syscall(SYS_gettid));			//< duan20200610
	//< 初始化UDP设置
	if (false == UDP_Init(&sock, BAKIO_PORT, 0, 0, UDP_SEND_STATUS, nullptr)) { return 0; }

	//< 开启接收备份数据的线程
	THREAD_CREATE_FAILED(Thread_Create("tRecvIOBak_ID", &tRecvIOBak_ID, NULL, SCHED_POLICY, 89, true, tRecvIOBak, CONTROL_CORE, NULL));

	//< 设置发送到的IP地址及端口
	Addr_Set(&NetC, BAKIO_PORT, inet_addr(NETC_IP_BC));

	//< 设置广播周期
	MS2TimeSpec(&time, BAKIO_PERIOD);

	//< 开启定时中断
	Timer_Create(&BakIOData_Timer, BakIOSIG, &time);
	while (1)
	{
		if (SYS_Role == Master_Twins_Role)
		{
			//< 等待信号量释放进行广播操作
			/*MUTEX_LOCK(BakIO_Mutex, "BakIO_Mutex lock failed");*/
			SEM_WAIT(BakIOSemId, "BakIOSemId wait failed");

			while (TYP_CARD_Count < TYP_MAX_CARD)					//< duan20200502添加
			{
				SaveChannel_Num = 0;
				//< 数据打包
				_iLen = BakIO_PACK_Make(Data2Send, Head, Tail, LIMIT_LEN, &SaveChannel_Num, &TYP_CARD_Count);			
				if (SaveChannel_Num > 0)
				{
					ExactDelay(EACH_UDP_PACK_SEND_DELAY_TIME);		//< Shike20210516 UDP包之间加一个小延时
					//< 发送数据
					if (-1 == UDP_Send(&sock, &NetC, (char*)Data2Send, _iLen))
						break;
				}
			}
			if (TYP_CARD_Count >= TYP_MAX_CARD)						//< duan20200502添加
				TYP_CARD_Count = 0;
		}
		else
			RoughDelay_S(2);
	}
	close(sock);//< 断开连接
#undef LIMIT_LEN
#undef PACK_MAXNUM
#undef EACH_UDP_PACK_SEND_DELAY_TIME
}
